#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#include "cJSON.h"
#include "shmem.h"

#define ADDRESS     "tcp://localhost:1883"
#define CLIENTID    "ExampleClientSub"
#define TOPIC       "demo"
#define PAYLOAD     "Hello World!"
#define QOS         1
#define TIMEOUT     10000L

volatile MQTTClient_deliveryToken deliveredtoken;

typedef struct student
{
    char name[16];
    int num;
    float avegrade;
}Student;

typedef struct commend
{
    int key;
    char name[16];
    int val;
}Cmd;


void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    int i;
    char* payloadptr;
    Student stu[3];
    //解析Json信息
    cJSON *para = cJSON_Parse(message->payload);
    cJSON *data = cJSON_GetObjectItem(para, "data");
    cJSON *data1 = cJSON_GetArrayItem(data, 0);
    cJSON *data2 = cJSON_GetArrayItem(data, 1);
    cJSON *data3 = cJSON_GetArrayItem(data, 2);

    cJSON *name1 = cJSON_GetObjectItem(data1, "name");
    cJSON *num1 = cJSON_GetObjectItem(data1, "num");
    cJSON *avegrade1 = cJSON_GetObjectItem(data1, "avegrade");

    cJSON *name2 = cJSON_GetObjectItem(data2, "name");
    cJSON *num2 = cJSON_GetObjectItem(data2, "num");
    cJSON *avegrade2 = cJSON_GetObjectItem(data2, "avegrade");

    cJSON *name3 = cJSON_GetObjectItem(data3, "name");
    cJSON *num3 = cJSON_GetObjectItem(data3, "num");
    cJSON *avegrade3 = cJSON_GetObjectItem(data3, "avegrade");

    //赋值给stu对象
    stu[0].num = num1->valueint;
    stu[0].avegrade = avegrade1->valuedouble;
    strcpy(stu[0].name, name1->valuestring);

    stu[1].num = num2->valueint;
    stu[1].avegrade = avegrade2->valuedouble;
    strcpy(stu[1].name, name2->valuestring);

    stu[2].num = num3->valueint;
    stu[2].avegrade = avegrade3->valuedouble;
    strcpy(stu[2].name, name3->valuestring);

    printf("Message arrived\n");
    printf("   topic: %s\n", topicName);

    //发送到共享内存
    struct shm_param shm_para;
    shm_init(&shm_para,"student",1024);
    Student *stu_ptr = (Student*)shm_getaddr(&shm_para);
    stu_ptr[0] = stu[0];
    stu_ptr[1] = stu[1];
    stu_ptr[2] = stu[2];

    putchar('\n');  
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

int main(int argc, char* argv[])
{
    // 定义MQTT客户端
    MQTTClient client;
    // 定义MQTT客户端链接选项
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    // 定义MQTT消息
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    // 定义MQTT消息令牌
    MQTTClient_deliveryToken token;
    // 发布MQTT消息
    pubmsg.qos = QOS;
    pubmsg.retained = 0;
    int rc;
    int ch;
    //创建MQTT客户端
    MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;//设置客户端与服务器保持连接的心跳间隔为 20 秒。
    conn_opts.cleansession = 1;//设置清除会话标志为 1，表示每次连接时都创建新会话。
    //设置MQTT客户端回调函数
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
    //连接MQTT客户端
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
    //订阅MQTT主题
    MQTTClient_subscribe(client, TOPIC, QOS);

    //等待用户输入
    do 
    {
        //获取共享内存数据
        struct shm_param cmd_para;
        shm_init(&cmd_para,"cmd",1024);
        Cmd *cmd_ptr = (Cmd*)shm_getaddr(&cmd_para);
        if(cmd_ptr->key!=0)
        {
            cJSON *cmd_root = cJSON_CreateObject();
            cJSON_AddNumberToObject(cmd_root,"key",cmd_ptr->key);
            cJSON_AddStringToObject(cmd_root,"name",cmd_ptr->name);
            cJSON_AddNumberToObject(cmd_root,"val",cmd_ptr->val);
            char cmd[1024];
            strcpy(cmd,cJSON_Print(cmd_root));
            //发送消息
            pubmsg.payloadlen = (int)strlen(cmd);
            pubmsg.payload = cmd;
            MQTTClient_publishMessage(client, "cmd", &pubmsg, &token);
            printf("key:%d ,name:%s ,val:%d\n",cmd_ptr->key,cmd_ptr->name,cmd_ptr->val);
            //删除共享内存
            shm_del(&cmd_para);
        }

    } while(ch!='Q' && ch != 'q');
    //取消订阅MQTT主题
    MQTTClient_unsubscribe(client, TOPIC);
    //断开MQTT连接
    MQTTClient_disconnect(client, 10000);
    //销毁MQTT客户端
    MQTTClient_destroy(&client);
    return rc;
}